﻿var asyncRequest = (function () {
    function handleReadyState(o, callback) {
        var poll = window.setInterval(function () {
            if (o && o.readyState == 4) {
                window.clearInterval(poll);
                if (callback) {
                    callback(o);
                }
            }
        }, 50);
    }

    var getXHR = function () {
        var http;
        try {
            http = new XMLHttpRequest;
            getXHR = function () {
                return new XMLHttpRequest;
            };
        } catch (e) {
            var msxml = [
                'MSXML2.XMLHTTP.3.0',
                'MSXML2.XMLHTTP',
                'Microsoft.XMLHTTP'
            ];
            for (var i = 0, len = msxml.length; i < len; ++i) {
                try {
                    http = new ActiveXObject(msxml[i]);
                    getXHR = function () {
                        return new ActiveXObject(msxml[i]);
                    };
                    break;
                } catch (e) { }
            }
        }
        return http;
    };

    return function (method, uri, callback, postData) {
        var http = getXHR();
        http.open(method, uri, true);
        handleReadyState(http, callback);
        http.send(postData || null);
        return http;
    }
})();


Function.prototype.method = function (name, fn) {
    this.prototype[name] = fn;
    return this;
};

if (!Array.prototype.forEach) {
    Array.method('forEach', function (fn, thisObj) {
        var scope = thisObj || window;
        for (var i = 0, len = this.length; i < len; i++) {
            fn.call(scope, this[i], i, this);
        }
    });
}

if (!Array.prototype.filter) {
    Array.method('filter', function (fn, thisObj) {
        var scope = thisObj || window;
        var a = [];
        for (var i = 0, len = this.length; i < len; i++) {
            if (!fn.call(scope, this[i], i, this)) {
                continue;
            }
            a.push(this[i]);
        }
        return a;
    });
}

//Observer System
window.DED = window.DED || {};
DED.util = DED.util || {};
DED.util.Observer = function () {
    this.fns = [];
};

DED.util.Observer.prototype = {
    subscribe: function (fn) {
        this.fns.push(fn);
    },
    unsubscribe: function (fn) {
        this.fns = this.fns.filter(function (el) {
            if (el !== fn) {
                return el;
            }
        });
    },
    fire: function (o) {
        this.fns.forEach(function (el) {
            el(o);
        });
    }
};

DED.Queue = function () {
    this.queue = [];

    this.onComplete = new DED.util.Observer;
    this.onFailure = new DED.util.Observer;
    this.onFlush = new DED.util.Observer;

    this.retryCount = 3;
    this.currentRetry = 0;
    this.paused = false;
    this.timeout = 5000;
    this.conn = {};
    this.timer = {};
};

DED.Queue.method('flush', function () {
    if (!this.queue.length > 0) {
        return;
    }
    if (this.paused) {
        this.paused = false;
        return;
    }
    var _this = this;
    this.currentRetry++;
    var abort = function () {
        _this.conn.abort();
        if (_this.currentRetry == _this.retryCount) {
            _this.onFailure.fire();
            _this.currentRetry = 0;
        } else {
            _this.flush();
        }
    };

    this.timer = window.setTimeout(abort, this.timeout);
    var callback = function (o) {
        window.clearTimeout(_this.timer);
        _this.currentRetry = 0;
        _this.queue.shift();
        _this.onFlush.fire(o.responseXML);
        if (_this.queue.length == 0) {
            _this.onComplete.fire();
            return;
        }
        _this.flush();
    };

    this.conn = asyncRequest(
        this.queue[0]['method'],
        this.queue[0]['uri'],
        callback,
        this.queue[0]['params']
    );
}).method('setRetryCount', function (count) {
    this.retryCount = count;

}).method('setTimeout', function (time) {
    this.timeout = time;

}).method('add', function (o) {
    this.queue.push(o);

}).method('pause', function (o) {
    this.paused = ture;

}).method('dequeue', function () {
    this.queue.pop();

}).method('clear', function (o) {
    this.queue = [];

});
